package org.theqcp.wow.sim.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.prefs.Preferences;

import javax.swing.ComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.theqcp.wow.sim.gui.net.ImportCharProgressFrame;
import org.theqcp.wow.sim.gui.tabs.Shaman;

public class EnhSimGUIFrame extends JFrame implements ActionListener, Runnable {

    private static final long serialVersionUID = -5668946230196128350L;

    protected final FileNameExtensionFilter charFileFilter = new FileNameExtensionFilter("EnhSim character data", "txt");
    protected final Preferences prefs = Preferences.userNodeForPackage(getClass());

    protected TreeMap<DataPoint, Component> dataPoints = new TreeMap<DataPoint, Component>();
    protected HashSet<DataPoint> talents = new HashSet<DataPoint>();

    protected String baseTitle = "EnhSimGUI/J";
    protected String lastFileName = null;

    protected ESGMenuBar esgMenuBar;
    protected Shaman esgSideBar;
    protected ESGMainPanel esgMainPanel;
    protected ESGStatusBar esgStatusBar;

    public EnhSimGUIFrame() {
	esgMenuBar = new ESGMenuBar(this);
	esgSideBar = new Shaman(this);
	esgMainPanel = new ESGMainPanel(this);
	esgStatusBar = new ESGStatusBar();

	setupFrame();
    }

    private void setupFrame() {
	URL url = this.getClass().getResource("/res/enhsim.png");

	if( url != null ) {
	    setIconImage(Toolkit.getDefaultToolkit().createImage(url));
	} else {
	    setIconImage(Toolkit.getDefaultToolkit().createImage("res/enhsim.png"));
	}

	setTitle(baseTitle);

	JPanel root = new JPanel();
	root.setLayout(new BorderLayout());

	root.add(esgMenuBar, BorderLayout.NORTH);
	root.add(esgSideBar, BorderLayout.WEST);
	root.add(esgMainPanel, BorderLayout.CENTER);
	root.add(esgStatusBar, BorderLayout.SOUTH);

	add(root);
    }

    public void addDataPoint( DataPoint point, Component awtComponent ) {
	dataPoints.put(point, awtComponent);
    }

    public String getDataPoint( DataPoint point ) {
	Component p = dataPoints.get(point);

	if( p instanceof JTextField ) {
	    return ((JTextField) p).getText();
	} else if( p instanceof JCheckBox ) {
	    return ((JCheckBox) p).isSelected() ? ("1") : ("0");
	} else if( p instanceof JComboBox ) {
	    return ((JComboBox) p).getSelectedItem().toString();
	}

	return "";
    }

    public Map<DataPoint, String> getDataPoints() {
	TreeMap<DataPoint, String> data = new TreeMap<DataPoint, String>();

	for( DataPoint d: dataPoints.keySet() ) {
	    if( d != DataPoint.rotation_priority ) {
		data.put(d, getDataPoint(d));
	    }
	}

	return data;
    }

    /**
     * Sets a data point to the specified value. If value is null, the data
     * point is set to the default value for its container.
     * 
     * @param point
     * @param value
     */
    public void setDataPoint( DataPoint point, Object value ) {
	Component p = dataPoints.get(point);

	if( p != null ) {
	    if( p instanceof JTextField ) {
		if( value == null ) {
		    ((JTextField) p).setText("");
		} else {
		    ((JTextField) p).setText(value.toString());
		}
	    } else if( p instanceof JCheckBox ) {
		if( value == null ) {
		    ((JCheckBox) p).setSelected(false);
		} else {
		    if( value.equals("0") ) {
			((JCheckBox) p).setSelected(false);
		    } else {
			((JCheckBox) p).setSelected(true);
		    }
		}
	    } else if( p instanceof JComboBox ) {
		if( value == null ) {
		    ((JComboBox) p).setSelectedIndex(0);
		} else {
		    JComboBox c = (JComboBox) p;
		    ComboBoxModel cm = c.getModel();
		    String test, v;
		    for( int i = 0; i < cm.getSize(); i++ ) {
			test = cm.getElementAt(i).toString().toLowerCase().replaceAll(" ", "_");
			v = value.toString().toLowerCase().replaceAll(" ", "_");
			if( v.equals(test) ) {
			    c.setSelectedIndex(i);
			    return;
			}
		    }
		}
	    } else {
		// TODO: Handle this better
		System.err.println(p);
	    }
	}
    }

    public void addTalent( DataPoint... points ) {
	for( DataPoint point: points ) {
	    talents.add(point);
	}
    }

    public boolean isTalent( DataPoint point ) {
	return talents.contains(point);
    }

    public int getTalentMax( DataPoint point ) {
	int max = 0;

	try {
	    Component o = dataPoints.get(point);
	    if( o instanceof JComboBox ) {
		JComboBox c = (JComboBox) o;

		String m = c.getModel().getElementAt(c.getModel().getSize() - 1).toString();

		max = Integer.valueOf(m);
	    }
	} catch( Throwable e ) {
	    SwingUtilities.invokeLater(new ScrollingExceptionDialog(e));
	}

	return max;
    }

    @Override
    public void run() {
	setDefaultCloseOperation(DISPOSE_ON_CLOSE);

	pack();
	setSize(700, 635);
	setResizable(false);
	setLocationByPlatform(true);
	setVisible(true);
    }

    @Override
    public void actionPerformed( ActionEvent event ) {
	String cmd = event.getActionCommand();
	if( cmd.equals("new_char") ) {
	    lastFileName = null;
	    setTitle(baseTitle);

	    for( DataPoint d: dataPoints.keySet() ) {
		setDataPoint(d, null);
	    }
	} else if( cmd.equals("load_char_file") || cmd.equals("save_char_file") || cmd.equals("save_as_char_file") ) {
	    String selected = lastFileName;

	    if( (selected == null) || !cmd.equals("save_char_file") ) {
		JFileChooser fc = new JFileChooser();
		File path = new File(prefs.get("last_file", ""));

		fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fc.addChoosableFileFilter(charFileFilter);

		if( path.canRead() ) {
		    fc.setCurrentDirectory(path.getParentFile());
		    fc.setSelectedFile(path);
		}

		int rv = fc.showOpenDialog(this);

		if( rv != JFileChooser.APPROVE_OPTION )
		    return;

		selected = fc.getSelectedFile().getAbsolutePath();
		lastFileName = selected;
	    }

	    EnhSimCharFile escf = new EnhSimCharFile(selected);

	    setTitle(String.format("%s - %s", baseTitle, selected));
	    prefs.put("last_file", selected);

	    try {
		if( cmd.equals("load_char_file") ) {
		    escf.read(this);
		}
		if( cmd.equals("save_char_file") || cmd.equals("save_as_char_file") ) {
		    escf.write(this);
		}
	    } catch( IOException e ) {
		SwingUtilities.invokeLater(new ScrollingExceptionDialog(e));
	    }
	    // } else if( cmd.equals("import_item_armory") ) {
	    // } else if( cmd.equals("import_item_head") ) {
	    // } else if( cmd.equals("import_item_wiki") ) {
	    // } else if( cmd.equals("enh_sim_start") ) {
	    // } else if( cmd.equals("enh_sim_calc_ep") ) {
	    // } else if( cmd.equals("about") ) {
	} else if( cmd.equals("import_char") ) {
	    ImportCharProgressFrame.loadCharacter(this, "Skywall", "Sheripiari");
	} else if( cmd.equals("exit") ) {
	    dispose();
	} else {
	    System.err.println(cmd);
	}
    }

}
